package com.np.retrofit211demo1.retrofit;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSONObject;
import com.np.retrofit211demo1.service.SystemService;
import com.np.retrofit211demo1.service.UltrasoundService;
import com.np.retrofit211demo1.util.GsonUtil;
import com.trello.rxlifecycle3.LifecycleTransformer;
import com.trello.rxlifecycle3.android.BuildConfig;

import org.jetbrains.annotations.Contract;
import org.reactivestreams.Publisher;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.CompletableTransformer;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.MaybeTransformer;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.SingleTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.fastjson.FastJsonConverterFactory;
import retrofit2.converter.jaxb.JaxbConverterFactory;

public class RetrofitFactory {

    private static RetrofitFactory mRetrofitFactory;
    private static OkHttpClient mOkHttpClient;

    private SystemService mSystemService;
    private UltrasoundService mUltrasoundService;

    private RetrofitFactory() {
        initRetrofit(false);
    }

    private void initRetrofit(boolean reset) {
        initOkHttpClient(reset);
        mSystemService = getRetrofitService(HttpConfig.getSystemApiHost(), SystemService.class);
        mUltrasoundService = getRetrofitService(HttpConfig.getUltraSoundApiHost(), UltrasoundService.class);
    }

    private static <T> T getRetrofitService(String service, Class<T> serviceClass) {
        Retrofit mRetrofit = new Retrofit.Builder()
                .baseUrl(service)
                .addConverterFactory(JaxbConverterFactory.create())
                .addConverterFactory(FastJsonConverterFactory.create())//FastJsonConverter
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器
                .client(mOkHttpClient)
                .build();
        return mRetrofit.create(serviceClass);
    }

    // 重置retrofit
    public void resetRetrofit() {
        initRetrofit(true);
    }

    @NonNull
    @Contract(value = "_ -> new", pure = true)
    public static ObservableTransformer normalTrans(LifecycleTransformer l) {
        return new normalTransformer(l);
    }

    public static final class normalTransformer<T> implements ObservableTransformer<T, T>,
            FlowableTransformer<T, T>,
            SingleTransformer<T, T>,
            MaybeTransformer<T, T>,
            CompletableTransformer {

        private final LifecycleTransformer lTrans;

        public normalTransformer(LifecycleTransformer l) {
            lTrans = l;
        }

        @Override
        public CompletableSource apply(Completable upstream) {
            return upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(lTrans);
        }

        @Override
        public Publisher<T> apply(Flowable<T> upstream) {
            return upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(lTrans);
        }

        @Override
        public MaybeSource<T> apply(Maybe<T> upstream) {
            return upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(lTrans);
        }

        @Override
        public ObservableSource<T> apply(Observable<T> upstream) {

            return upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(lTrans);
        }

        @Override
        public SingleSource<T> apply(Single<T> upstream) {
            return upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(lTrans);
        }


    }

    // 单例模式获取 OkHttpClient
    private static void initOkHttpClient(boolean reset) {
        if (mOkHttpClient == null || reset) {
            synchronized (RetrofitFactory.class) {
                if (mOkHttpClient == null) {
                    // 指定缓存路径,缓存大小100Mb

//                    Cache cache = new Cache(new File(HttpConfig.DIR_CACHE_FILE, "HttpCache"),
//                            1024 * 1024 * 100);

                    OkHttpClient.Builder builder = new OkHttpClient.Builder()
                            //设置连接超时时间
                            .connectTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
                            //设置读取超时时间
                            .readTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
                            //设置写入超时时间
                            .writeTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
                            //默认重试一次
                            .retryOnConnectionFailure(true)
                            //添加header拦截器
                            .addInterceptor(InterceptorHelper.getHeaderInterceptor())
                            //添加特殊错误处理拦截器
                            .addInterceptor(InterceptorHelper.getWellHomeExceptionInterceptor());

                    //添加缓存拦截器
//                            .addInterceptor(InterceptorHelper.getCacheInterceptor())
                    //添加重试拦截器
//                            .addInterceptor(InterceptorHelper.getRetryInterceptor())
                    // 信任Https,忽略Https证书验证
                    // https认证,如果要使用https且为自定义证书 可以去掉这两行注释，并自行配制证书。
//                            .sslSocketFactory(SSLSocketTrust.getSSLSocketFactory())
//                            .hostnameVerifier(SSLSocketTrust.getHostnameVerifier())
                    //缓存
//                            .cache(cache)

                    if (BuildConfig.DEBUG) {

                        builder //添加请求头拦截器
//                            .addInterceptor(InterceptorHelper.getHeaderInterceptor())
                                //添加日志拦截器
                                .addInterceptor(InterceptorHelper.getLogInterceptor());

                    }

                    mOkHttpClient = builder.build();
                }
            }
        }
    }

    public static RetrofitFactory getInstance() {
        if (mRetrofitFactory == null) {
            synchronized (RetrofitFactory.class) {
                if (mRetrofitFactory == null) {
                    mRetrofitFactory = new RetrofitFactory();
                }
            }

        }
        return mRetrofitFactory;
    }

    public SystemService getSystemService() {
        return mSystemService;
    }

    public UltrasoundService getUltrasoundService() {
        return mUltrasoundService;
    }

    public static RequestBody getJSONRequestBodyFromEntries(Map<String, String> paramsMap) {

        String content = GsonUtil.gson().toJson(paramsMap);

        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), content);

        return body;

    }

    public static RequestBody getJSONRequestBodyFromObject(Object o) {

        String content = JSONObject.toJSONString(o);

        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), content);

        return body;

    }

    public static RequestBody getJSONRequestBodyFromParams(String... params) {

        if (params.length == 0 || params.length % 2 != 0) {
            throw new IllegalArgumentException("参数的数量不正确");
        }

        HashMap<String, String> map = new HashMap<>();

        for (int i = 0; i * 2 + 1 < params.length; i++) {
            map.put(params[i * 2], params[i * 2 + 1]);
        }

        return getJSONRequestBodyFromEntries(map);


    }
}